001    /*
002     * Copyright 2004-2005 Stephen McConnell
003     *
004     * Licensed  under the  Apache License,  Version 2.0  (the "License");
005     * you may not use  this file  except in  compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *   http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed  under the  License is distributed on an "AS IS" BASIS,
012     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
013     * implied.
014     *
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package net.dpml.util;
020    
021    import java.io.File;
022    import java.io.FileNotFoundException;
023    import java.io.InputStream;
024    import java.util.ArrayList;
025    import java.util.Properties;
026    
027    import javax.xml.parsers.DocumentBuilder;
028    import javax.xml.parsers.DocumentBuilderFactory;
029    
030    import org.w3c.dom.Document;
031    import org.w3c.dom.Element;
032    import org.w3c.dom.Node;
033    import org.w3c.dom.NodeList;
034    
035    /**
036     * Utility class supporting the translation of DOM content into local child, children,
037     * attribute and value values.
038     *
039     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
040     * @version 1.0.1
041     */
042    public final class ElementHelper
043    {
044        private ElementHelper()
045        {
046            // utility class
047        }
048    
049       /**
050        * Return the root element of the supplied file.
051        * @param definition the file to load
052        * @return the root element
053        * @exception Exception if the error occurs during root element establishment
054        */
055        public static Element getRootElement( final File definition )
056          throws Exception
057        {
058            if( !definition.exists() )
059            {
060                throw new FileNotFoundException( definition.toString() );
061            }
062    
063            if( !definition.isFile() )
064            {
065                final String error =
066                  "Source is not a file: " + definition;
067                throw new IllegalArgumentException( error );
068            }
069    
070            final DocumentBuilderFactory factory =
071            DocumentBuilderFactory.newInstance();
072            factory.setValidating( false );
073            factory.setNamespaceAware( false );
074            final Document document =
075              factory.newDocumentBuilder().parse( definition );
076            return document.getDocumentElement();
077        }
078    
079       /**
080        * Return the root element of the supplied input stream.
081        * @param input the input stream containing a XML definition
082        * @return the root element
083        * @exception Exception if an error occurs
084        */
085        public static Element getRootElement( final InputStream input )
086          throws Exception
087        {
088            final DocumentBuilderFactory factory =
089              DocumentBuilderFactory.newInstance();
090            factory.setValidating( false );
091            factory.setNamespaceAware( false );
092            factory.setExpandEntityReferences( false );
093            DocumentBuilder builder = factory.newDocumentBuilder();
094            return getRootElement( builder, input );
095        }
096    
097       /**
098        * Return the root element of the supplied input stream.
099        * @param builder the document builder
100        * @param input the input stream containing a XML definition
101        * @return the root element
102        * @exception Exception if an error occurs
103        */
104        public static Element getRootElement( final DocumentBuilder builder, final InputStream input )
105          throws Exception
106        {
107            final Document document = builder.parse( input );
108            return document.getDocumentElement();
109        }
110    
111       /**
112        * Return a named child relative to a supplied element.
113        * @param root the parent DOM element
114        * @param name the name of a child element
115        * @return the child element of null if the child does not exist
116        */
117        public static Element getChild( final Element root, final String name )
118        {
119            if( null == root )
120            {
121                return null;
122            }
123            Element[] children = getChildren( root );
124            for( int i=0; i<children.length; i++ )
125            {
126                Element child = children[i];
127                if( name.equals( child.getTagName() ) )
128                {
129                    return child;
130                }
131            }
132            return null;
133        }
134    
135       /**
136        * Return all children matching the supplied element name.
137        * @param root the parent DOM element
138        * @param name the name against which child element will be matched
139        * @return the array of child elements with a matching name
140        */
141        public static Element[] getChildren( final Element root, final String name )
142        {
143            if( null == root )
144            {
145                return new Element[0];
146            }
147            Element[] children = getChildren( root );
148            final ArrayList result = new ArrayList();
149            for( int i=0; i<children.length; i++ )
150            {
151                final Element child = children[i];
152                if( name.equals( child.getTagName() ) )
153                {
154                    result.add( child );
155                }
156            }
157            return (Element[]) result.toArray( new Element[0] );
158        }
159    
160       /**
161        * Return all children of the supplied parent.
162        * @param root the parent DOM element
163        * @return the array of all children
164        */
165        public static Element[] getChildren( final Element root )
166        {
167            if( null == root )
168            {
169                return new Element[0];
170            }
171            final NodeList list = root.getChildNodes();
172            final int n = list.getLength();
173            if( n < 1 )
174            {
175                return new Element[0];
176            }
177            final ArrayList result = new ArrayList();
178            for( int i=0; i < n; i++ )
179            {
180                final Node item = list.item( i );
181                if( item instanceof Element )
182                {
183                    result.add( item );
184                }
185            }
186            return (Element[]) result.toArray( new Element[0] );
187        }
188    
189       /**
190        * Return the value of an element.
191        * @param node the DOM node
192        * @return the node value
193        */
194        public static String getValue( final Element node )
195        {
196            if( null == node )
197            {
198                return null;
199            }
200            String value;
201            if( node.getChildNodes().getLength() > 0 )
202            {
203                value = node.getFirstChild().getNodeValue();
204            }
205            else
206            {
207                value = node.getNodeValue();
208            }
209            //return normalize( value );
210            return value;
211        }
212    
213       /**
214        * Return the value of an element attribute.
215        * @param node the DOM node
216        * @param key the attribute key
217        * @return the attribute value or null if the attribute is undefined
218        */
219        public static String getAttribute( final Element node, final String key )
220        {
221            return getAttribute( node, key, null );
222        }
223    
224       /**
225        * Return the value of an element attribute.
226        * @param node the DOM node
227        * @param key the attribute key
228        * @param def the default value if the attribute is undefined
229        * @return the attribute value or the default value if undefined
230        */
231        public static String getAttribute( final Element node, final String key, final String def )
232        {
233            if( null == node )
234            {
235                return def;
236            }
237            if( !node.hasAttribute( key ) )
238            {
239                return def;
240            }
241            //final String value = node.getAttribute( key );
242            //return normalize( value );
243            return node.getAttribute( key );
244        }
245    
246       /**
247        * Return the value of an element attribute as a boolean
248        * @param node the DOM node
249        * @param key the attribute key
250        * @return the attribute value as a boolean or false if undefined
251        */
252        public static boolean getBooleanAttribute( final Element node, final String key )
253        {
254            return getBooleanAttribute( node, key, false );
255        }
256    
257       /**
258        * Return the value of an element attribute as a boolean.
259        * @param node the DOM node
260        * @param key the attribute key
261        * @param def the default value if the attribute is undefined
262        * @return the attribute value or the default value if undefined
263        */
264        public static boolean getBooleanAttribute( final Element node, final String key, final boolean def )
265        {
266            if( null == node )
267            {
268                return def;
269            }
270    
271            if( !node.hasAttribute( key ) )
272            {
273                return def;
274            } 
275    
276            String value = node.getAttribute( key );
277            value = normalize( value );
278            if( value.equals( "" ) )
279            {
280                return def;
281            }
282            if( value.equalsIgnoreCase( "true" ) )
283            {
284                return true;
285            }
286            if( value.equalsIgnoreCase( "false" ) )
287            {
288                return false;
289            }
290            final String error =
291              "Boolean argument [" + value + "] not recognized.";
292            throw new IllegalArgumentException( error );
293        }
294    
295       /**
296        * Parse the value for any property tokens relative to system properties.
297        * @param value the value to parse
298        * @return the normalized string
299        */
300        static String normalize( String value )
301        {
302            return normalize( value, System.getProperties() );
303        }
304    
305       /**
306        * Parse the value for any property tokens relative to the supplied properties.
307        * @param value the value to parse
308        * @param props the reference properties
309        * @return the normalized string
310        */
311        static String normalize( String value, Properties props )
312        {
313            return PropertyResolver.resolve( props, value );
314        }
315    }